package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sc.nft.dao.BoxTakePoolDao;
import com.sc.nft.dao.EquityPropsDao;
import com.sc.nft.dao.PropEquityVestInDao;
import com.sc.nft.dao.PropGiftDao;
import com.sc.nft.dao.TaskDrawPrizeDao;
import com.sc.nft.dao.UserEquityPropsDao;
import com.sc.nft.dao.UserEquityPropsLogDao;
import com.sc.nft.dao.UserInfoDao;
import com.sc.nft.entity.BoxTakePool;
import com.sc.nft.entity.EquityProps;
import com.sc.nft.entity.PropEquityVestIn;
import com.sc.nft.entity.PropGift;
import com.sc.nft.entity.UserInfo;
import com.sc.nft.entity.congestive.EquityPropsCT;
import com.sc.nft.entity.dto.AddEquityPropsGiftDTO;
import com.sc.nft.entity.dto.MerchantAvailabilityListDTO;
import com.sc.nft.entity.dto.UserEquityIdDTO;
import com.sc.nft.entity.dto.VistInFlagDTO;
import com.sc.nft.entity.dto.VistInFlagUserDTO;
import com.sc.nft.entity.vo.AirdropGrantEquityPropsVO;
import com.sc.nft.entity.vo.EquityPropsDetailVO;
import com.sc.nft.entity.vo.EquityPropsExpiredLogPageVO;
import com.sc.nft.entity.vo.EquityPropsGetLogPageVO;
import com.sc.nft.entity.vo.EquityPropsUseLogPageVO;
import com.sc.nft.entity.vo.GetCoinCertificateVO;
import com.sc.nft.entity.vo.MallEquityPropsGetLogPageVO;
import com.sc.nft.entity.vo.MallEquityPropsVO;
import com.sc.nft.entity.vo.MerchantAvailabilityListVO;
import com.sc.nft.entity.vo.PageAdminEquityPropsVO;
import com.sc.nft.entity.vo.ProdctAssociateEquityPropsVO;
import com.sc.nft.entity.vo.UserEquityPropsDetailVO;
import com.sc.nft.enums.EquityPropsTypeEnum;
import com.sc.nft.enums.UserEquityPropsGetTypeEnum;
import com.sc.nft.enums.UserEquityPropsUseTypeEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.EquityPropsService;
import com.sc.nft.sup.ErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * 权益道具表服务接口实现
 *
 * @author Sun
 * @description 由 Mybatisplus Code Generator 创建
 * @since 2023-03-28 10:29:22
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class EquityPropsServiceImpl implements EquityPropsService {
    private final EquityPropsDao equityPropsDao;
    private final BoxTakePoolDao boxTakePoolDao;
    private final UserEquityPropsDao userEquityPropsDao;
    private final UserEquityPropsLogDao userEquityPropsLogDao;
    private final PropGiftDao propGiftDao;
    private final TaskDrawPrizeDao taskDrawPrizeDao;
    private final UserInfoDao userInfoDao;
    private final PropEquityVestInDao propEquityVestInDao;

    @Override
    public Page<PageAdminEquityPropsVO> getPageAdminEquityProps(String firstTitle, Boolean status, Boolean showFlag, Integer pageNo, Integer pageSize) {
        Page<PageAdminEquityPropsVO> pageAdminEquityProps = equityPropsDao.getPageAdminEquityProps(firstTitle, status, showFlag, pageNo, pageSize);
        pageAdminEquityProps.getRecords().forEach(pageAdminEquityPropsVO -> {
            if (pageAdminEquityPropsVO.getIsGift()) {
                List<PropGift> propGifts = propGiftDao.getByPropId(pageAdminEquityPropsVO.getId());
                pageAdminEquityPropsVO.conversionConfiguration(propGifts);
            }
        });
        return pageAdminEquityProps;
    }

    @Override
    public void addEquityProps(String firstTitle, String getRulesUrl, String creationContent, String productDetails, Boolean isExpired, Integer expiredDay, Boolean isBrandUse, EquityPropsTypeEnum typeClassify, Boolean isGift, Integer aging, AddEquityPropsGiftDTO addEquityPropsGiftDTO, Long vistIn, Long daoId) {
        EquityProps equityProps = new EquityProps();
        equityProps.setFirstTitle(firstTitle);
        equityProps.setCreationContent(creationContent);
        equityProps.setProductDetails(productDetails);
        equityProps.setDaoId(daoId);
        equityProps.setIsBrandUse(isBrandUse);
        equityProps.setStatus(Boolean.FALSE);
        equityProps.setTypeClassify(typeClassify);
        equityProps.setIsGift(isGift);
        equityProps.setAging(aging);
        equityProps.setVistIn(vistIn);
        if (isExpired) {
            equityProps.setExpiredDay(expiredDay);
        } else {
            equityProps.setExpiredDay(3650);
        }
        equityProps.setProductUuid("SP" + IdUtil.getSnowflakeNextIdStr());
        equityProps.insert();
        // 开启了转增
        if (isGift) {
            EquityPropsCT addEquityPropsCT = new EquityPropsCT();
            addEquityPropsCT.transition(addEquityPropsGiftDTO, equityProps.getId());
            propGiftDao.saveBatch(addEquityPropsCT.getPropGifts());
        } else {
            propGiftDao.deleteByPropId(equityProps.getId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editEquityProps(Long id, String getRulesUrl, String firstTitle, String creationContent, String productDetails, Boolean isExpired, Integer expiredDay, Boolean isBrandUse, EquityPropsTypeEnum typeClassify, Boolean isGift, Integer aging, AddEquityPropsGiftDTO addEquityPropsGiftDTO, Long vistIn, Long daoId) {

        EquityProps propsDaoById = equityPropsDao.getById(id);
        Assert.isFalse(ObjectUtil.isEmpty(propsDaoById), () -> new GlobalRunTimeException(ErrorCode.EQUITY_PROPS_DO_NOT_EXIST));

        EquityProps equityProps = new EquityProps();
        equityProps.setId(id);
        equityProps.setFirstTitle(firstTitle);
        equityProps.setCreationContent(creationContent);
        equityProps.setProductDetails(productDetails);
        equityProps.setIsBrandUse(isBrandUse);
        equityProps.setDaoId(daoId);
        equityProps.setTypeClassify(typeClassify);
        equityProps.setGetRulesUrl(getRulesUrl);
        equityProps.setIsGift(isGift);
        equityProps.setAging(aging);
        equityProps.setVistIn(vistIn);
        if (isExpired) {
            equityProps.setExpiredDay(expiredDay);
        } else {
            equityProps.setExpiredDay(3650);
        }
        Assert.isTrue(equityProps.updateById(), () -> new GlobalRunTimeException(ErrorCode.FAIL_TO_EDIT));
        // 开启了转增
        if (isGift) {
            // 删掉所有的转增配置后重新新增
            propGiftDao.deleteByPropId(id);
            EquityPropsCT addEquityPropsCT = new EquityPropsCT();
            addEquityPropsCT.transition(addEquityPropsGiftDTO, equityProps.getId());
            propGiftDao.saveBatch(addEquityPropsCT.getPropGifts());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editEquityPropsStatus(Long id, Boolean status) {
        EquityProps propsDaoById = equityPropsDao.getById(id);
        Assert.isFalse(ObjectUtil.isEmpty(propsDaoById), () -> new GlobalRunTimeException(ErrorCode.EQUITY_PROPS_DO_NOT_EXIST));
        Assert.isTrue(equityPropsDao.updateStatusById(id, status), () -> new GlobalRunTimeException(ErrorCode.FAIL_TO_EDIT));
    }

    @Override
    public Page<ProdctAssociateEquityPropsVO> prodctAssociateEquityProps(Integer pageNo, Integer pageSize, String firstTitle) {
        return equityPropsDao.prodctAssociateEquityProps(new Page<>(pageNo, pageSize), firstTitle);
    }

    @Override
    public EquityProps getById(Long id) {
        return equityPropsDao.getById(id);
    }

    @Override
    public Page<AirdropGrantEquityPropsVO> airdropGrantEquityProps(Page page, String firstTitle, Integer typeClassify) {
        return equityPropsDao.airdropGrantEquityProps(page, firstTitle, typeClassify);
    }

    @Override
    public GetCoinCertificateVO findByIdGetCoinCertificate(Long id, UserInfo userInfo) {
        GetCoinCertificateVO getCoinCertificateVO = new GetCoinCertificateVO();
        BoxTakePool boxTakePool = boxTakePoolDao.getById(id);
        Integer havingCountByUserId = userEquityPropsDao.getHavingCountByUserId(boxTakePool.getPropsId(), userInfo.getId());
        getCoinCertificateVO.setCount(havingCountByUserId);
        return getCoinCertificateVO;
    }

    @Override
    public void editEquityPropsShowFlag(Long id, Boolean showFlag) {
        EquityProps propsDaoById = equityPropsDao.getById(id);
        Assert.isFalse(ObjectUtil.isEmpty(propsDaoById), () -> new GlobalRunTimeException(ErrorCode.EQUITY_PROPS_DO_NOT_EXIST));
        Assert.isTrue(equityPropsDao.updateShowFlagById(id, showFlag), () -> new GlobalRunTimeException(ErrorCode.FAIL_TO_EDIT));
    }

    @Override
    public Page<MerchantAvailabilityListVO> simpleAvailabilityList(MerchantAvailabilityListDTO merchantAvailabilityListDTO) {
        return equityPropsDao.simpleAvailabilityList(merchantAvailabilityListDTO);
    }

    @Override
    public Page<MerchantAvailabilityListVO> equityPropAllPage(Page page) {
        return equityPropsDao.equityPropAllPage(page);
    }

    @Override
    public EquityPropsDetailVO getDetail(String firstTitle) {
        EquityPropsDetailVO result = new EquityPropsDetailVO();

        EquityProps equityProps = equityPropsDao.getByFirstTitle(firstTitle);
        if (ObjectUtil.isNull(equityProps)) {
            return result;
        }
        result.setFirstTitle(firstTitle);
        //持有这个权益道具的人数
        Integer userCount = userEquityPropsDao.getHasUserCountByEquityId(equityProps.getId());
        result.setHasUserCount(userCount);
        //未领取数量(只有任务奖励会未领取)
        Integer unPickCount = taskDrawPrizeDao.getCountByEquityId(equityProps.getId());
        result.setUnPickCount(unPickCount);
        //已领取数量(包括用户已经消耗/过期/冻结的)
        Integer pickCount = userEquityPropsDao.getSumCountByEquityId(equityProps.getId());
        result.setPickCount(pickCount);
        //正常持有数量（即正常+冻结）
        Integer normalCount = userEquityPropsDao.getCanUseCountByEquityId(equityProps.getId());
        //流通数量 = 未领取数量 + 正常持有数量
        result.setSumCount((ObjectUtil.isNull(unPickCount) ? 0 : unPickCount) + (ObjectUtil.isNull(normalCount) ? 0 : normalCount));
        return result;
    }

    @Override
    public Page<EquityPropsGetLogPageVO> getLog(Long propId, String userTel, String firstTitle, UserEquityPropsGetTypeEnum getType, Date startTime, Date endTime, Integer pageNo, Integer pageSize) {
        Long userId = null;
        if (StrUtil.isNotBlank(userTel)) {
            UserInfo userInfo = userInfoDao.getOneByUserTel(userTel);
            if (ObjectUtil.isNull(userInfo)) {
                return new Page<>(pageNo, pageSize);
            }
            userId = userInfo.getId();
        }

        if (propId != null) {
            EquityProps equityProps = equityPropsDao.getById(propId);
            firstTitle = equityProps.getFirstTitle();
        }
        Page<EquityPropsGetLogPageVO> result = userEquityPropsLogDao.getLog(null, userId, firstTitle, getType, startTime, endTime, pageNo, pageSize);
        result.getRecords().forEach(e -> e.setGetTypeName(e.getGetType().getDescription()));
        return result;
    }

    @Override
    public Page<MallEquityPropsGetLogPageVO> mallPropsGetLog(Long userId, UserEquityPropsGetTypeEnum getType, Integer pageNo,
                                                             Integer pageSize) {
        Page<MallEquityPropsGetLogPageVO> result = userEquityPropsLogDao.mallPropsGetLog(userId, getType, pageNo,
                pageSize);
        return result;
    }

    @Override
    public Page<EquityPropsUseLogPageVO> useLog(String userTel, String firstTitle, UserEquityPropsUseTypeEnum useType, Date startTime, Date endTime, Integer pageNo, Integer pageSize) {
        Long userId = null;
        if (StrUtil.isNotBlank(userTel)) {
            UserInfo userInfo = userInfoDao.getOneByUserTel(userTel);
            if (ObjectUtil.isNull(userInfo)) {
                return new Page<>(pageNo, pageSize);
            }
            userId = userInfo.getId();
        }
        Page<EquityPropsUseLogPageVO> result = userEquityPropsLogDao.useLog(userId, firstTitle, useType, startTime, endTime, pageNo, pageSize);
        result.getRecords().forEach(e -> e.setUseTypeName(e.getUseType().getDescription()));
        return result;
    }

    @Override
    public Page<EquityPropsExpiredLogPageVO> expiredLog(String userTel, String firstTitle, Date startTime, Date endTime, Integer pageNo, Integer pageSize) {
        Long userId = null;
        if (StrUtil.isNotBlank(userTel)) {
            UserInfo userInfo = userInfoDao.getOneByUserTel(userTel);
            if (ObjectUtil.isNull(userInfo)) {
                return new Page<>(pageNo, pageSize);
            }
            userId = userInfo.getId();
        }
        return userEquityPropsDao.expiredLog(userId, firstTitle, startTime, endTime, pageNo, pageSize);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteEquityProps(Long id) {
        //未领取数量
        Integer unPickCount = taskDrawPrizeDao.getCountByEquityId(id);
        //正常持有数量（即正常+冻结）
        Integer normalCount = userEquityPropsDao.getCanUseCountByEquityId(id);
        //流通数量 = 未领取数量 + 正常持有数量
        Integer sumCount = ((ObjectUtil.isNull(unPickCount) ? 0 : unPickCount) + (ObjectUtil.isNull(normalCount) ? 0 : normalCount));
        if (sumCount > 0) {
            throw new GlobalRunTimeException("该道具卡流通数量不为0，无法删除");
        }
        Assert.isTrue(equityPropsDao.deleteEquityProps(id), () -> new GlobalRunTimeException("删除失败"));
    }

    @Override
    public Page<MerchantAvailabilityListVO> getLongTermEquityPropPage(String firstTitle, Integer type, Page page) {
        return equityPropsDao.getLongTermEquityPropPage(page, firstTitle, type);
    }

    /**
     * 获取商城上架中的权益道具
     *
     * @return
     */
    @Override
    public IPage<MallEquityPropsVO> getMallEquityProps(VistInFlagDTO vist) {
        PropEquityVestIn propEquityVestIn = propEquityVestInDao.getFlag(vist.getFlag());
        if (propEquityVestIn == null) {
            throw new GlobalRunTimeException("无效的访问标识");
        }
        return equityPropsDao.getMallEquityProps(vist.getPageNo(), vist.getPageSize(), propEquityVestIn.getId(), vist.getFirstTitle());
    }

    /**
     * 商城用户持有的权益道具
     *
     * @param vistInFlagUserDTO
     * @return
     */
    @Override
    public List<MallEquityPropsVO> getUserEquityProps(VistInFlagUserDTO vistInFlagUserDTO) {
        return userEquityPropsDao.getUserEquityProps(vistInFlagUserDTO);
    }

    /**
     * 用户指定权益道具列表
     *
     * @param userEquityIdDTO
     * @return
     */
    @Override
    public Page<UserEquityPropsDetailVO> userEquityIdList(UserEquityIdDTO userEquityIdDTO) {
        // 验证当前的标识是否存在.且验证的道具是否是该标识下的
        PropEquityVestIn flag = propEquityVestInDao.getFlag(userEquityIdDTO.getVistIn());
        if (BeanUtil.isEmpty(flag)) {
            throw new GlobalRunTimeException(ErrorCode.EQUITY_PROPS_DO_NOT_EXIST);
        }
        EquityProps equityProps = equityPropsDao.getById(userEquityIdDTO.getPropEquityId());
        if (!equityProps.getVistIn().equals(flag.getId())) {
            throw new GlobalRunTimeException(ErrorCode.EQUITY_PROPS_DO_NOT_EXIST);
        }
        Page<UserEquityPropsDetailVO> resultPage = userEquityPropsDao.getMyEquityDetail(userEquityIdDTO.getUserId(), userEquityIdDTO.getPropEquityId(), 0, userEquityIdDTO.toMp(), Boolean.FALSE);
        return resultPage;
    }

}